#include "core.h"
#include "IStringList.h"

// ....................................................................................................................
// Porovnavacia metoda pre qsort - vzostupne triedenie
// Vstup:
//			pArg1, pArg2 - argumenty
// Vystup:
//			podla porovnania
// ....................................................................................................................
INT32 IStringListCompare_Asc(CONST_PVOID pArg1, CONST_PVOID pArg2) {
	return (*(IString**)pArg1)->CaseCompare(*(IString**)pArg2);
}
// ....................................................................................................................
// ....................................................................................................................
// Porovnavacia metoda pre qsort - zostupne triedenie
// Vstup:
//			pArg1, pArg2 - argumenty
// Vystup:
//			podla porovnania
// ....................................................................................................................
INT32 IStringListCompare_Desc(CONST_PVOID pArg1, CONST_PVOID pArg2) {
	return -(*(IString**)pArg1)->CaseCompare(*(IString**)pArg2);
}
// ....................................................................................................................

// ....................................................................................................................
// Konstruktor
// Vstup:
//			Ziaden
// Vystup:
//			Ziaden
// ....................................................................................................................
IStringList::IStringList(void) {
}
// ....................................................................................................................
// ....................................................................................................................
// Destruktor
// Vstup:
//			Ziaden
// Vystup:
//			Ziaden
// ....................................................................................................................
IStringList::~IStringList(void) {
	Clear(); // Uvolnim z pamate
}
// ....................................................................................................................
// ....................................................................................................................
// Ziskanie poctu zaznamov
// Vstup:
//			Ziaden
// Vystup:
//			Pocet zaznamov
// ....................................................................................................................
INT32 __fastcall IStringList::Count(void) {
	return FItems.Count; 
}
// ....................................................................................................................
// ....................................................................................................................
// Uvolnenie zoznamu z pamate
// Vstup:
//			Ziaden
// Vystup:
//			Ziaden
// ....................................................................................................................
void __fastcall IStringList::Clear(void) {
	for (INT32 i = 0; i < FItems.Count; i++) delete (IString*)FItems.Items[i]; // Zrusim vsetky retazca
	FItems.Clear(); // Uvolnim zoznam
}
// ....................................................................................................................
// ....................................................................................................................
// Zaradenie zaznamu na koniec
// Vstup:
//			pValue - retazec
//			pData - data objektu
// Vystup:
//			Pozicia noveho zaznamu
// ....................................................................................................................
INT32 __fastcall IStringList::Add(CONST_PCHAR pValue, PVOID pData) {
	IString *S = new IString(pValue); S->UserData = pData; // Vytvorim objekt pre ulozenie retazca
	return FItems.Add(S); // Zaradim a vratim poziciu
}
// ....................................................................................................................
// ....................................................................................................................
// Zaradenie zaznamu na koniec
// Vstup:
//			pValue - retazec
//			pLength - dlzka retazca
//			pData - data objektu
// Vystup:
//			Pozicia noveho zaznamu
// ....................................................................................................................
INT32 __fastcall IStringList::Add(CONST_PCHAR pValue, INT32 pLength, PVOID pData) {
	IString *S = new IString(pValue, pLength); S->UserData = pData; // Vytvorim objekt pre ulozenie retazca
	return FItems.Add(S); // Zaradim a vratim poziciu
}
// ....................................................................................................................
// ....................................................................................................................
// Zaradenie zaznamu na zadanu poziciu
// Vstup:
//			pIndex - pozicia na ulozenie
//			pValue - retazec
//			pData - data objektu
// Vystup:
//			Pozicia noveho zaznamu
// ....................................................................................................................
INT32 __fastcall IStringList::Insert(INT32 pIndex, CONST_PCHAR pValue, PVOID pData) {
	IString *S = new IString(pValue); S->UserData = pData; // Vytvorim objekt pre ulozenie retazca
	return FItems.Insert(pIndex, S); // Zaradim a vratim poziciu
}
// ....................................................................................................................
// ....................................................................................................................
// Ziskanie objektu
// Vstup:
//			pIndex - pozicia objektu
// Vystup:
//			Smernik na objekt alebo NULL
// ....................................................................................................................
IString* __fastcall IStringList::GetString(INT32 pIndex) {
	return ICore::IsValidIndex(pIndex, 0, FItems.Count) ? (IString*)FItems.Items[pIndex] : NULL;
}
// ....................................................................................................................
// ....................................................................................................................
// Vytvorenie kopie obsahu objektu
// Vstup:
//			pSource - objekt pre skopirovanie obsahu
// Vystup:
//			Ziaden
// ....................................................................................................................
void __fastcall IStringList::CreateCopy(IStringList *pSource) {
	Clear(); // Zrusim aktualny obsah
	FItems.Allocate(pSource->FItems.Count, false); // Alokujem pamat pre zoznam
	INT32 C = pSource->FItems.Count; // Ziskam pocet zaznamov
	for (INT32 i = 0; i < C; i++) {
		IString *S = (IString*)pSource->FItems.Items[i]; // Ziskam objekt
		IString *S1 = new IString(S); S1->UserData = S->UserData; // Vytvorim kopiu
		FItems.Add(S1); // Vlozim do zoznamu
	}
}
// ....................................................................................................................
// ....................................................................................................................
// Vymazanie zaznamu
// Vstup:
//			pIndex - pozicia zaznamu
// Vystup:
//			Ziaden
// ....................................................................................................................
void __fastcall IStringList::Delete(INT32 pIndex) {
	if (!ICore::IsValidIndex(pIndex, 0, FItems.Count)) return; // Test platnosti indexu
	delete (IString*)FItems.Items[pIndex]; // Zrusim retazec
	FItems.Delete(pIndex); // Vymazem zo zoznamu
}
// ....................................................................................................................
// ....................................................................................................................
// Hladanie zaznamu od zadanej pozicie
// Vstup:
//			pValue - hladany retazec
//			pStart - zaciatok hladania
// Vystup:
//			pozicia alebo -1
// ....................................................................................................................
INT32 __fastcall IStringList::Find(CONST_PCHAR pValue, INT32 pStart, INT32 pLength) {
	if (!ICore::IsValidIndex(pStart, 0, FItems.Count)) return -1; // Test platnosti zaciatku
	if (pLength == -1) {
		for (INT32 i = pStart; i < FItems.Count; i++) { // Prejdem vsetky zaznamy
			if (*((IString*)FItems.Items[i]) == pValue) return i; // Porovnavam
		}
	} else {
		for (INT32 i = pStart; i < FItems.Count; i++) { // Prejdem vsetky zaznamy
			if (((IString*)FItems.Items[i])->Compare(pValue, 0, pLength)) return i; // Porovnavam
		}
	}
	return -1; // Nic som nenasiel
}
// ....................................................................................................................
// ....................................................................................................................
// Hladanie zaznamu od zadanej pozicie bez ohladu na velkost pismen
// Vstup:
//			pValue - hladany retazec
//			pStart - zaciatok hladania
// Vystup:
//			pozicia alebo -1
// ....................................................................................................................
INT32 __fastcall IStringList::CaseFind(CONST_PCHAR pValue, INT32 pStart, INT32 pLength) {
	if (!ICore::IsValidIndex(pStart, 0, FItems.Count)) return -1; // Test platnosti zaciatku
	if (pLength == -1) {
		for (INT32 i = pStart; i < FItems.Count; i++) { // Prejdem vsetky zaznamy
			if (((IString*)FItems.Items[i])->CaseCompare(pValue) == 0) return i; // Porovnavam
		}
	} else {
		for (INT32 i = pStart; i < FItems.Count; i++) { // Prejdem vsetky zaznamy
			if (((IString*)FItems.Items[i])->CaseCompare(pValue, 0, pLength) == 0) return i; // Porovnavam
		}
	}
	return -1; // Nic som nenasiel
}
// ....................................................................................................................
// ....................................................................................................................
// Vytvorenie zoznamu z retazca
// Vstup:
//			pValue - retazec
//			pSeparator - oddelovac
//			pSkipEmpty - priznak preskocenia zaradenia prazdneho retazca
// Vystup:
//			Ziaden
// ....................................................................................................................
void __fastcall IStringList::CreateFromString(IString *pValue, CHAR pSeparator, bool pSkipEmpty) {
	Clear(); // Vycistim aktualny obsah
	INT32 I = 0; // Zaciatok hladania
	INT32 L = pValue->Length; // Dlzka vstupu

	while(true) {
		INT32 I1 = pValue->FindChar(pSeparator, I);
		if (I1 == -1) { // Nic? 
			if (L - I == 0) {
				if (!pSkipEmpty) Add("");
			}
			else Add(pValue->Value + I, L - I); 
			return;
		}
		if (I1 - I == 0) {
			if (!pSkipEmpty) Add("");
		}
		else Add(pValue->Value + I, I1 - I);
		I = I1 + 1; // Dalsi riadok
	}
}
// ....................................................................................................................
// ....................................................................................................................
// Skopirovanie obsahu objektu
// Vstup:
//			pValue - objekt pre skopirovanie
// Vystup:
//			Ziaden
// ....................................................................................................................
void __fastcall IStringList::Assign(IStringList* pValue) {
	Clear(); // Uvolnim aktualny zoznam
	
	INT32 C = pValue->FItems.Count; // Ziskam pocet zaznamov
	for (INT32 i = 0; i < C; i++) {
		IString *S = (IString*)pValue->FItems.Items[i]; // Ziskanie objektu
		IString *S1 = new IString(S); S1->UserData = S->UserData; // Vytvorenie kopie
		FItems.Add(S1); // Zaradim do zoznamu
	}
}
// ....................................................................................................................
// ....................................................................................................................
// Zotriedenie zoznamu
// Vstup:
//			pDirection - smer triedenia
// Vystup:
//			Ziaden
// ....................................................................................................................
void __fastcall IStringList::Sort(bool pDirection, INT32 pStart, INT32 pCount) {
	FItems.Sort(pDirection ? IStringListCompare_Asc : IStringListCompare_Desc, pStart, pCount);
}
// ....................................................................................................................
// ....................................................................................................................
// Priprava zoznamu na binarne vyhladavanie
// Vstup:
//			Ziaden
// Vystup:
//			Ziaden
// ....................................................................................................................
void __fastcall IStringList::PrepareForBinarySearch(void) {
	FItems.Sort(IStringListCompare_Asc);
}
// ....................................................................................................................
// ....................................................................................................................
// Najdenie pozicie zoznamu pomocou binarneho vyhladavania
// Vstup:
//			pValue - hladana hodnota
// Vystup:
//			pozicia alebo -1
// ....................................................................................................................
INT32 __fastcall IStringList::BinarySearch(CONST_PCHAR pValue) {

	INT32 Min = 0, Max = FItems.Count - 1;
	if (Max == -1) return -1; // Prazdny zoznam?

	while(true) {
		if (Min + 1 == Max) { // Posledne dve?
			if (((IString*)FItems.Items[Min])->Compare(pValue) == 0) return Min;
			if (((IString*)FItems.Items[Max])->Compare(pValue) == 0) return Max;
			return -1; // Nic sa nenaslo
		}
		INT32 Mid = Min + (Max - Min) / 2;
		INT32 R = ((IString*)FItems.Items[Mid])->Compare(pValue);
		if (R == 0) return Mid;
		if (R < 0) Min = Mid;
		else Max = Mid;
	}
}
// ....................................................................................................................
// ....................................................................................................................
// Ulozenie obsahu do suboru
// Vstup:
//			pFileName - nazov suboru
//			pSkipEmty - priznak preskocenia prazdneho retazca
//			pTrimmed - priznak vykonania trim pred ulozenim
// Vystup:
//			true / false
// ....................................................................................................................
bool __fastcall IStringList::SaveToFile(CONST_PCHAR pFileName, bool pSkipEmpty, bool pTrimmed) {
	FILE *F = fopen(pFileName, "wt+"); // Vytvorim subor
	if (F == NULL) return false; // Chyba?

	INT32 C = FItems.Count; // Ziskam pocet
	bool B = true;

	IString S1; S1.Allocate(1024);

	for (INT32 i = 0; i < C; i++) {
		IString *S = (IString*)FItems.Items[i]; // Ziskam string
		if ((pSkipEmpty) || (pTrimmed)) {
			if (pTrimmed) {
				S1 = S; S1.Trim(); S = &S1;
			}
			if ((S->Length == 0) && (pSkipEmpty)) continue;
		}
		fprintf(F, "%s\n", S->PChar()); // Ulozim
		if (ferror(F) != 0) { // Chyba?
			B = false;
			break;
		}
	}

	fclose(F); // Uzatvorim subor
	return B;
}
// ....................................................................................................................
// ....................................................................................................................
// Nacitanie obsahu zo suboru
// Vstup:
//			pFileName - nazov suboru
//			pSkipEmty - priznak preskocenia prazdneho retazca
//			pTrimmed - priznak vykonania trim pred ulozenim
// Vystup:
//			true / false
// ....................................................................................................................
bool __fastcall IStringList::LoadFromFile(CONST_PCHAR pFileName, bool pSkipEmpty, bool pTrimmed) {
	FILE *F = fopen(pFileName, "rt"); // Vytvorim subor
	if (F == NULL) return false; // Chyba?

	Clear(); // Uvolnim aktualny obsah
	IString S1; S1.Allocate(1024);

	bool B = true;
	while(S1.ReadLineFromFile(F)) { // Nacitavam riadky
		if (ferror(F)) { // Chyba?
			B = false;
			break;
		}
		if (pTrimmed) S1.Trim();
		if ((pSkipEmpty) && (S1.Length == 0)) continue;
		Add(S1.PChar()); // Zaradim
	}

	fclose(F); // Uzatvorim subor
	return B;
}
// ....................................................................................................................
// ....................................................................................................................
// Zhustenie zoznamu retazcov do jedneho s oddelenim
// Vstup:
//			pSeparator - oddelovac jednotlivych retazcov
// Vystup:
//			Result - vysledok
// ....................................................................................................................
void __fastcall IStringList::ToString(IString *Result, CONST_PCHAR pSeparator) {
	Result->Truncate();

	INT32 C = FItems.Count - 1;
	for (INT32 i = 0; i <= C; i++) { // Prejdem vsetky zaznamy
		Result->Append((IString*)FItems.Items[i]); 
		if (i != C) Result->Append(pSeparator);
	}
}
// ....................................................................................................................
